added Feb 2001 SDK
[windows-sources.git] / shared source / wpf / src / host / dll / progresspage.cxx
blob520ef5551dd9fd51d7ae3f8adf1167f49f41306c
1 //+-----------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // Description:
6 // Deployment progress page. See .hxx.
7 //
8 // History:
9 // 2007/12/xx [....] Created
11 //------------------------------------------------------------------------
13 #include "Precompiled.hxx"
14 #include "ProgressPage.hxx"
15 #include "DllMain.hxx"
16 #include "OleDocument.hxx"
17 #include "HTMLPageHost.hxx"
18 #include "Utilities.hxx"
19 #include "psapi.h" // For GetMappedFileName()
22 CProgressPage::~CProgressPage()
24 // Normally, the page should be explicitly hidden before interfaces are released.
25 // Hide() is called here to help ensure orderly cleanup, just in case.
26 Hide();
29 void CProgressPage::Init(IProgressPageHost *pHost)
31 ASSERT(!m_pHost && pHost);
32 m_pHost = pHost;
35 HRESULT GetFilePathFromDevicePath(__in_ecount(MAX_PATH) LPCTSTR pszDevicePath, __out_ecount(MAX_PATH) LPTSTR pszFilePath)
37 // Translate path with device name to drive letters.
39 // Originally we tried to use GetLogicalDriveStrings/QueryDosDevice to map the
40 // path but on server 2003 this fails with an access denied error in QueryDosDevice.
41 // This is the way suggested by MSDN here: http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
43 // So, since (at least for this release) we always get installed to the Windows directory
44 // we can use that as a basis for some string manipulation to convert the device path
45 // to a dos path.
47 HRESULT hr = S_OK;
49 wchar_t *pszWindowsDirName = pszFilePath;
50 wchar_t szDevicePath[MAX_PATH];
51 CKHR(StringCchCopy(szDevicePath, MAX_PATH, pszDevicePath)); // a copy that I can lower case
53 // 1) get windows directory, remove drive letter
54 CKHR(SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, 0, pszFilePath));
55 pszWindowsDirName += 3; // trim "c:\"
57 _wcslwr_s(pszFilePath, MAX_PATH);
58 _wcslwr_s(szDevicePath, MAX_PATH);
60 // 2) find the windows directory name in device path
61 const wchar_t* pszPath = wcsstr(szDevicePath, pszWindowsDirName);
62 if (pszPath == NULL)
64 CKHR(E_UNEXPECTED);
67 // 3) append path (including windows dir) on to original drive letter
68 *pszWindowsDirName = '\0';
69 CKHR(StringCchCat(pszFilePath, MAX_PATH, pszPath));
71 Cleanup:
72 return hr;
75 HRESULT CProgressPage::Show()
77 if(IsActive())
78 return S_FALSE;
80 HRESULT hr;
81 HMODULE hModule = NULL;
82 CComPtr<IUnknown> spContainerUnknown;
83 CComPtr<IMoniker> spMoniker;
84 CComPtr<IBindCtx> spBindCtx;
86 m_hHostWindow = m_pHost->GetHostWindow();
87 if(!m_hHostWindow)
88 return E_UNEXPECTED;
89 CKHR(CHTMLPageHostingHelper::CreateHTMLDocumentControl(m_hHostWindow, 0, &spContainerUnknown, &m_spHtmlDocument));
90 m_spControlHost = spContainerUnknown;
92 // Load the progress page from res:// URL via IPersistMoniker. If IHTMLDocument2::put_URL() is called
93 // instead, IE 7 decides to create a new top-level window!
95 wchar_t progressPageURL[MAX_PATH] = L"res://";
98 // On WinXP, LoadMUILibrary (and thus LoadResourceDLL) return an HMODULE which
99 // is a handle to a memory mapped file, not a "real" HMODULE. Because of
100 // this we have to jump through some hoops to get the fully qualified filename
101 // of the MUI file.
104 // Load the associated resource DLL so that we can get its path via GetMappedFileName,
105 // this returns us a device path, so convert the device path to a file path.
106 hModule = LoadResourceDLL();
107 CHECK_NULL_FROM_WIN32(hModule);
108 wchar_t devicePath[MAX_PATH];
109 CHECK_ZERO_FROM_WIN32(GetMappedFileName(GetCurrentProcess(), hModule, devicePath, MAX_PATH));
110 wchar_t filePath[MAX_PATH];
111 CKHR(GetFilePathFromDevicePath(devicePath, filePath));
113 // The MUI library gets loaded as a memory mapped file, so we want to
114 // free it here and call LoadLibrary() on the actual file so that IE
115 // can load resources from the root file path.
116 FreeMUILibrary(hModule);
117 hModule = NULL;
118 m_hostDllMuiModule = LoadLibrary(filePath);
119 CHECK_NULL_FROM_WIN32(m_hostDllMuiModule);
121 CKHR(StringCchCat(progressPageURL, MAX_PATH, filePath));
122 CKHR(StringCchCat(progressPageURL, MAX_PATH, L"/ProgressPage.html"));
123 CKHR(CreateURLMoniker(NULL, progressPageURL, &spMoniker));
125 CKHR(CreateBindCtx(0, &spBindCtx));
126 CKHR(CComQIPtr<IPersistMoniker>(m_spHtmlDocument)->Load(true/*try [....]*/, spMoniker, spBindCtx, 0));
128 CKHR(CComQIPtr<IHTMLDocument>(m_spHtmlDocument)->get_Script(&m_spDocumentScript));
129 CKHR(m_spControlHost->SetExternalDispatch(static_cast<IDispatch*>(this)));
131 Cleanup:
133 if (hModule)
135 FreeMUILibrary(hModule);
136 hModule = NULL;
139 m_bFailed = FAILED(hr);
140 return hr;
143 HRESULT CProgressPage::Hide()
145 if(m_spHtmlDocument == NULL) // Hide even if we failed to initialize completely
146 return S_FALSE;
148 HRESULT hr = S_OK;
149 if (m_spControlHost)
151 hr = m_spControlHost->AttachControl(NULL, NULL);
153 m_spControlHost.Release();
154 m_spHtmlDocument.Release();
155 m_spDocumentScript.Release();
157 if (m_hostDllMuiModule)
159 FreeLibrary(m_hostDllMuiModule);
160 m_hostDllMuiModule = NULL;
163 // **BEWARE**: This call may cause all interface references to be released, which will delete the object.
164 if (m_pHost)
166 m_pHost->OnProgressPageClosed();
169 return hr;
172 HRESULT CProgressPage::TranslateAcceleratorIO(__in MSG *pMsg)
174 if(m_spHtmlDocument != NULL)
176 // When focus is on the progress page, we want at least the basic navigation keys to work.
177 // The hosted HTMLDocument object and the top-level browser are not aware of each other...
178 if(CHTMLPageHostingHelper::HandleNavigationKeys(*pMsg))
179 return S_OK;
181 // Crude heuristic: inferring when the HTML page is shown. There is no notification about that.
182 // The DHTML onload event usually occurs earlier. We want the progress page to be really shown
183 // before we get bogged down in loading the managed assemblies, which on cold start takes a long time.
184 // The HTMLDocument window will necessarily get WM_PAINT so that it can show anything. It may, however,
185 // not render all the content in response to the first WM_PAINT, because it loads and parses content
186 // asynchonously. Practically, it seems to show the basic page text on first render, and then the
187 // images may come a little later. This works out just fine for us.
188 // See also COleObject::DoVerb().
189 if(!m_bRendered && pMsg->message == WM_PAINT && GetParent(pMsg->hwnd) == m_hHostWindow)
191 m_bPartialRendered = true; //(Used for debugging if nothing else.)
192 if(m_bLoaded)
194 m_bRendered = true;
195 EventWriteWpfHostUm_ProgressPageShown();
196 m_pHost->OnProgressPageRendered();
200 return S_FALSE;
203 //[IDispatch implementation begin]
205 // Notifications coming from script in the HTML page
206 const LONG DISPID_CANCEL = 7;
207 const LONG DISPID_ONLOADED = 8;
209 HRESULT CProgressPage::GetIDsOfNames(
210 REFIID, __in_ecount(cNames) LPOLESTR *pNames, UINT cNames, LCID, __out_ecount(cNames) DISPID* rgDispId)
212 if(cNames == 1)
214 if(wcscmp(pNames[0], L"OnLoaded") == 0)
216 *rgDispId = DISPID_ONLOADED;
217 return S_OK;
219 if(wcscmp(pNames[0], L"Cancel") == 0)
221 *rgDispId = DISPID_CANCEL;
222 return S_OK;
225 return DISP_E_UNKNOWNNAME;
228 STDMETHODIMP CProgressPage::Invoke(DISPID dispidMember,
229 __in_ecount(1) REFIID, LCID, WORD, __in_ecount(1) DISPPARAMS *,
230 __out_ecount(1) VARIANT * pVarResult,
231 __out_ecount_opt(1) EXCEPINFO * pExcepInfo, __out_ecount_opt(1) UINT * puArgErr)
233 switch(dispidMember)
235 case DISPID_ONLOADED:
236 m_bLoaded = true;
237 // Note this is only 'logical load'. The page is likely not rendered yet. See the WM_PAINT detection.
238 return S_OK;
239 case DISPID_CANCEL:
240 return m_pHost->ExecOLECommand(OLECMDID_STOP);
241 default:
242 return DISP_E_MEMBERNOTFOUND;
246 //[IDispatch implementation end]
248 // "Nonstandard extension used : class rvalue used as lvalue"
249 // This warning occurs when passing &CComVariant(value) as a method parameter.
250 // It's awkward to declare local varibles for this. Suppressing the warning is safe for input-only VARIANTs.
251 #pragma warning(disable: 4238)
253 HRESULT CProgressPage::ShowProgressMessage(BSTR message)
255 if(!IsActive())
256 return E_UNEXPECTED;
257 ASSERT(m_bLoaded); // If not, we'll get DISP_E_UNKNOWNNAME below.
258 return m_spDocumentScript.Invoke1(L"ShowProgressMessage", &CComVariant(message));
261 HRESULT CProgressPage::SetApplicationName(BSTR appName)
263 if(!IsActive())
264 return E_UNEXPECTED;
265 ASSERT(m_bLoaded); // If not, we'll get DISP_E_UNKNOWNNAME below.
266 return m_spDocumentScript.Invoke1(L"SetApplicationName", &CComVariant(appName));
269 HRESULT CProgressPage::SetPublisherName(BSTR publisherName)
271 if(!IsActive())
272 return E_UNEXPECTED;
273 return m_spDocumentScript.Invoke1(L"SetPublisherName", &CComVariant(publisherName));
276 HRESULT CProgressPage::OnDownloadProgress(UINT64 bytesDownloaded, UINT64 bytesTotal)
278 if(!IsActive())
279 return E_UNEXPECTED;
280 // Passing 64-bit ints to script (or via IDispatch) doesn't seem to work.
281 // That's why the contract is to pass KB.
282 return m_spDocumentScript.Invoke2(L"OnDownloadProgress",
283 &CComVariant(UINT((bytesDownloaded+512)/1024)), &CComVariant(UINT((bytesTotal+512)/1024)));